/*
+--------------------------
| FreeloaderOS v0.0.1
|  - Microkernel
+--------------------------
| Written by Alec Hussey
| Copyright (c) 2007
|  - Deus X Foundation
+---------------------------
*/

/*
 * Global Descriptor Table
 */

#include <sys/system.h>
#include <sys/gdt.h>

/*
Setup descriptor in GDT.
*/
void gdt_set_gate(int num, 
                  unsigned long base, 
                  unsigned long limit, 
                  unsigned char access, 
                  unsigned char gran)
{
	// Setup descriptor base address
	gdt[num].base_low = (base & 0xFFFF);
	gdt[num].base_middle = (base >> 16) & 0xFF;
	gdt[num].base_high = (base >> 24) & 0xFF;
	
	// Setup descriptor limits
	gdt[num].limit_low = (limit & 0xFFFF);
	gdt[num].granularity = ((limit >> 16) & 0x0F);
	
	// Setup granularity and permissions flags
	gdt[num].granularity |= (gran & 0xF0);
	gdt[num].access = access;
}

/*
Setup special GDT pointer, setup 
the first 3 entries, and then call 
gdt_flush() in the assembly to tell 
the CPU where the new GDT is located 
and update the new segment registers.
*/
void init_gdt()
{
	// Setup GDT pointer and limit.
	gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
	gp.base = &gdt;
	
	// First entry point: Null Descriptor
	// Our null descriptor for CPU protection
	gdt_set_gate(0, 0, 0, 0, 0);
	
	// Second entry point: Code Segment
	gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
	
	// Third entry point: Data Segment
	gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
	
	// Flush out old GDT and update the new changes
	gdt_flush();
}
